package com.atguigu.gmall.ums.service.impl;

import com.atguigu.gmall.common.consts.GmallConsts;
import com.atguigu.gmall.common.utils.AlibabaHttpUtils;
import com.atguigu.gmall.common.utils.RandomUtils;
import com.atguigu.gmall.ums.config.AliyunSmsProperties;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.ums.mapper.UserMapper;
import com.atguigu.gmall.ums.entity.UserEntity;
import com.atguigu.gmall.ums.service.UserService;



@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AliyunSmsProperties aliyunSmsProperties;

    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<UserEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<UserEntity>()
        );

        return new PageResultVo(page);
    }

    @Override
    public Boolean checkLogin(String data, Integer type) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        switch (type){
            case 1:queryWrapper.eq(UserEntity::getUsername,data);break;
            case 2:queryWrapper.eq(UserEntity::getPhone,data);break;
            case 3:queryWrapper.eq(UserEntity::getEmail,data);break;
            default:return null;
        }
        return this.count(queryWrapper) == 0;
    }


    @Override
    public void register(UserEntity userEntity, String code) {
        //TODO:校验验证码
//        String phone = userEntity.getPhone();
//        String redisCode = stringRedisTemplate.opsForValue().get(GmallConsts.REGIST_CODE_PREFIX + phone);
//        if (StringUtils.equals(redisCode,code)){
//            throw new RuntimeException("验证码有误");
//        }

        //生成盐
        String salt = StringUtils.substring(UUID.randomUUID().toString(), 0, 6);
        //密码加盐加密存储
        userEntity.setPassword(DigestUtils.md5Hex(userEntity.getPassword() + salt));
        //新增用户
        userEntity.setLevelId(1l);
        userEntity.setSalt(salt);
        userEntity.setNickname("游客"+StringUtils.substring(UUID.randomUUID().toString(),0,5));
        userEntity.setSourceType(1);
        userEntity.setIntegration(1000);
        userEntity.setGrowth(1000);
        userEntity.setStatus(1);
        userEntity.setCreateTime(new Date());
        this.save(userEntity);

//        //TODO:删除验证码
//        stringRedisTemplate.delete(GmallConsts.REGIST_CODE_PREFIX + phone);
    }

    @Override
    public UserEntity queryUser(String loginName, String password) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        //非空判断
        if (StringUtils.isBlank(loginName) || StringUtils.isBlank(password)){
            throw new RuntimeException("用户名或密码有误");
        }
        //根据用户名查询用户
        queryWrapper.eq(UserEntity::getUsername,loginName).or().eq(UserEntity::getPhone,loginName)
                .or().eq(UserEntity::getEmail,loginName);

        UserEntity userEntity = this.getOne(queryWrapper);
        if (userEntity == null){
            throw new RuntimeException("用户名不存在");
        }
        //获取盐
        String salt = userEntity.getSalt();
        //对比传入的密码加盐后是否与数据库密码一致
        if (!StringUtils.equals(DigestUtils.md5Hex(password + salt),userEntity.getPassword())){
            throw new RuntimeException("用户名或密码有误");
        }


        return userEntity;
    }

    @Override
    public void isRegisted(String phone) {
        UserEntity userEntity = this.getOne(new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getPhone, phone));
        if (userEntity != null){
            throw new RuntimeException("用户已存在");
        }

        //验证码校验。一天只能获取5条，2分钟内只能获取1次
        String countKey = GmallConsts.CODE_COUNT_PREFIX + phone;
        String count = stringRedisTemplate.opsForValue().get(countKey);
        if (count != null && Integer.parseInt(count)>5){
            throw new RuntimeException("今日获取验证码次数超过限制");
        }
        String limitKey = GmallConsts.LIMIT_KEY_PREFIX + phone;
        Boolean limit = stringRedisTemplate.hasKey(limitKey);
        if (limit){
            throw new RuntimeException("2分钟内只能获取1条");
        }

        //生成验证码，调用第三方接口，并且缓存到redis中
        String code = RandomUtils.getFourBitRandom();
        System.out.println("====验证码===="+code);
        String host = aliyunSmsProperties.getHost();
        String path = aliyunSmsProperties.getPath();
        String method = "POST";
        String appcode = aliyunSmsProperties.getAppcode();
        HashMap<String, String> headers = new HashMap<>();
        headers.put("Authorization", "APPCODE " + appcode);
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap();
        Map<String, String> bodys = new HashMap();
        bodys.put("content", "code:"+code);
        bodys.put("phone_number", phone);
        bodys.put("template_id", "CST_ptdie100");
        try {
            HttpResponse response = AlibabaHttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println("===打印响应码==="+response.getStatusLine().getStatusCode());

            //短信发送成功，将短信存入到redis中,并设置过期时间
            stringRedisTemplate.opsForValue().set(GmallConsts.REGIST_CODE_PREFIX + phone,code,5, TimeUnit.MINUTES);

            //更新手机号获取验证码的次数,获取码次数校验，2分钟只能获取1次，一天只能获取五条
            stringRedisTemplate.opsForValue().set(limitKey,"1",2, TimeUnit.MINUTES);

            //自增，再之前的基础上+1，如果key不存在，则默认为0，在0的基础上+1
            Long increment = stringRedisTemplate.opsForValue().increment(countKey);
            if (increment == 1){
                //如果是第一次获取验证码，就给次数key设置1天过期时间，因为一天只能获取2条
                stringRedisTemplate.expire(countKey,1,TimeUnit.DAYS);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

}

